/*
    使用方法：面向对象
    
    需求：
        1.点击开始按钮
        2.移动
        3.吃=>变长
        4.碰到墙=>挂了;显示最终得分
        5.暂停/继续游戏
*/

var sw = 20, sh = 20,/* 方块宽 高 */
    tr = 30, td = 30;/* 行 列数 */
var snake = null;//蛇的实例
var food = null;//食物的实例
var game = null;//游戏的实例

// 定义方块 
function Square(x, y, classname) {
    //1: 0,0（实际要得到的）   =>0,0(传进来的)
    //2: 20,0  =>1,0
    //3: 40,0  =>2,0
    this.x = x * sw;
    this.y = y * sh;
    this.class = classname;

    // 方块用dom元素表示出来=>方块对于的DOM元素
    this.viewContent = document.createElement('div');
    this.viewContent.className = this.class;
    this.parent = document.getElementById('snakeWrap');//方块的父级
}
// 定义方块方法=>创建方块DOM
Square.prototype.create = function () {
    this.viewContent.style.position = 'absolute';
    this.viewContent.style.width = sw + 'px';
    this.viewContent.style.height = sh + 'px';
    this.viewContent.style.left = this.x + 'px';
    this.viewContent.style.top = this.y + 'px';

    // 添加到页面里
    this.parent.appendChild(this.viewContent);
}
// 删除方块方块
Square.prototype.remove = function () {
    this.parent.removeChild(this.viewContent);
}



// 创建蛇
function Snake() {
    this.head = null;//存蛇头信息
    this.tail = null;//存蛇尾信息
    this.pos = [];//存储蛇身上所有方块的位置

    //存储蛇走的方向，用一个对象表示
    this.directionNum = {
        left: { x: -1, y: 0, rotate: 180 },
        right: { x: 1, y: 0, rotate: 0 },
        up: { x: 0, y: -1, rotate: -90 },
        down: { x: 0, y: 1, rotate: 90 }
    }
}
// 定义蛇方法=>初始化
Snake.prototype.init = function () {
    // 一个蛇头，两个蛇身
    var snakeHead = new Square(2, 0, 'snakeHead');
    // console.log(1);
    snakeHead.create();//添加到页面
    this.head = snakeHead;//更新蛇头存储信息
    this.pos.push([2, 0]);//更新蛇头位置信息

    var snakeBody1 = new Square(1, 0, 'snakeBody');
    snakeBody1.create();//添加到页面
    this.pos.push([1, 0]);//更新位置信息

    var snakeBody2 = new Square(0, 0, 'snakeBody');
    snakeBody2.create();//添加到页面
    this.tail = snakeBody2;//更新蛇尾存储信息
    this.pos.push([0, 0]);//更新蛇尾位置信息

    // 链表关系
    snakeHead.last = null;
    snakeHead.next = snakeBody1;

    snakeBody1.last = snakeHead;
    snakeBody1.next = snakeBody2;

    snakeBody2.last = snakeBody1;
    snakeBody2.next = null;

    // 给蛇添加默认走的方向
    this.direction = this.directionNum.right;
}
// 用来获取蛇头的下一个位置
Snake.prototype.getNextPos = function () {
    var nextPos = [
        this.head.x / sw + this.direction.x,
        this.head.y / sh + this.direction.y
    ]
    // console.log(nextPos);

    // 下个点是自己，代表撞到了自己，游戏结束
    var selfCollied = false;//是否撞到了自己
    this.pos.forEach(function (value) {
        if (value[0] == nextPos[0] && value[1] == nextPos[1]) {
            // 如果数组中的两个数据都相等，就说明下一个点在蛇身上里面能找到
            selfCollied = true;
        }
    });
    if (selfCollied) {
        console.log('撞到自己了');

        this.strategies.die();
        return;
    }
    // 下个点是围墙，代表撞到了围墙，游戏结束
    if (nextPos[0] < 0 || nextPos[1] < 0 || nextPos[0] > td - 1 || nextPos[1] > tr - 1) {
        console.log('撞到墙上了');

        this.strategies.die();
        return;
    }
    // 下个点是食物，吃
    // this.strategies.eat();
    if (food && food.pos[0] == nextPos[0] && food.pos[1] == nextPos[1]) {
        this.strategies.eat.call(this);
        return;
    }

    // 下个点是什么都不是，走
    // this.strategies.move();
    this.strategies.move.call(this);
}
// 处理碰撞后要做得事
Snake.prototype.strategies = {
    move: function (format) {/* format决定是否删除最后一个方块（蛇尾）。传了这个参数，就表示是吃 */
        // console.log('move');  
        // console.log(this);

        // 创建新的身体(在旧蛇头的位置)
        var newBody = new Square(this.head.x / sw, this.head.y / sh, 'snakeBody');
        // 更新链表关系
        newBody.next = this.head.next;
        newBody.next.last = newBody;
        newBody.last = null;

        this.head.remove();//旧蛇头从原来位置删除
        newBody.create();//把蛇身插入

        // 创建新的蛇头
        var newHead = new Square(this.head.x / sw + this.direction.x, this.head.y / sh + this.direction.y, 'snakeHead');
        // 更新链表关系
        newHead.next = newBody;
        newHead.last = null;
        newHead.viewContent.style.transform = 'rotate(' + (this.direction.rotate - 90) + 'deg)';//修改蛇头方向,-90:图片初始的改变的
        newBody.last = newHead;

        newHead.create();

        // 更新所有坐标
        this.pos.splice(0, 0, [this.head.x / sw + this.direction.x, this.head.y / sh + this.direction.y]);/* 插入蛇头坐标 */
        this.head = newHead;//更新蛇头的信息

        if (!format) {/* 如果format的值为false，表示需要删除（除了吃之外的操作 ） */
            /* 
            1.删除旧蛇尾  、位置
            2.更新新蛇尾 

            */
            this.tail.remove();
            this.tail = this.tail.last;

            this.pos.pop();/* pop删除 */
        }
    },
    eat: function () {
        // console.log('eat');
        this.strategies.move.call(this, true);

        createFood();//吃完后又继续生成新食物
        game.score++;
    },
    die: function () {
        // console.log('die');
        game.over();
    },
}

snake = new Snake();


// 创建食物
function createFood() {
    /*
    1.随机生成方块 
    2.不能在墙，蛇身上
    */
    //食物的随机坐标
    var x = null;
    var y = null;

    var include = true;//循环跳出的条件,true表示食物的坐标在蛇身上(需要继续循环),false坐标不在蛇身上（不循环）
    while (include) {
        x = Math.round(Math.random() * (td - 1));/* Math.round四舍五入 */
        y = Math.round(Math.random() * (tr - 1));/* Math.round四舍五入 */

        snake.pos.forEach(function (value) {
            if (x != value[0] && y != value[1]) {
                // 随机坐标不在蛇身上
                include = false;
            }
        });
    }

    // 生成食物
    food = new Square(x, y, 'food');
    food.pos = [x, y];//存储生成食物的坐标，用于跟蛇头要走的下一个点做对比
    // food.remove();//报错    //删除旧的食物

    var foodDom = document.querySelector('.food');
    if (foodDom) {
        foodDom.style.left = x * sw + 'px';
        foodDom.style.top = y * sh + 'px';
    } else {
        food.create();
    }
}



// 创建游戏逻辑
function Game() {
    this.timer = null;
    this.score = 0;
}
Game.prototype.init = function () {
    snake.init();
    // snake.getNextPos();
    createFood();

    document.onkeydown = function (ev) {
        if (ev.which == 37 && snake.direction != snake.directionNum.right) {//左键
            snake.direction = snake.directionNum.left;
        } else if (ev.which == 38 && snake.direction != snake.directionNum.down) {//向上键
            snake.direction = snake.directionNum.up;
        } else if (ev.which == 39 && snake.direction != snake.directionNum.left) {//向右键
            snake.direction = snake.directionNum.right;
        } else if (ev.which == 40 && snake.direction != snake.directionNum.up) {//向下键
            snake.direction = snake.directionNum.down;
        }
    }

    this.start();
}
Game.prototype.start = function () {//开始游戏
    this.timer = setInterval(function () {
        snake.getNextPos();
    }, 200);
}
Game.prototype.pause = function () {
    clearInterval(this.timer);
}
Game.prototype.over = function () {
    clearInterval(this.timer);
    alert('你的得分为：' + this.score);

    // 游戏回到初始状态
    var snakeWrap = document.getElementById('snakeWrap');
    snakeWrap.innerHTML = '';

    snake = new Snake();
    game = new Game();

    var startBtnWarp = document.querySelector('.startBtn');
    startBtnWarp.style.display = 'block';
}

// 开启游戏
game = new Game();
var startBtn = document.querySelector('.startBtn button');
startBtn.onclick = function () {
    startBtn.parentNode.style.display = 'none';
    game.init();
}

// 暂停游戏
var snakeWrap = document.getElementById('snakeWrap');
var pauseBtn = document.querySelector('.pauseBtn button');
snakeWrap.onclick = function () {
    game.pause();

    pauseBtn.parentNode.style.display = 'block';
}
pauseBtn.onclick = function () {
    game.start();
    pauseBtn.parentNode.style.display = 'none';
}

